Many of the advanced features of this
package, such as defun*, loop, and
setf, are implemented as Lisp macros. In
byte-compiled code, these complex notations will be expanded into
equivalent Lisp code which is simple and efficient. For example,
the forms
(incf i n)
(push x (car p))
are expanded at compile-time to the Lisp forms
(setq i (+ i n))
(setcar p (cons x (car p)))
which are the most efficient ways of doing
these respective operations in Lisp. Thus, there is no
performance penalty for using the more readable incf
and push forms in your compiled code.
Interpreted code, on the other hand, must expand
these macros every time they are executed. For this reason it is
strongly recommended that code making heavy use of macros be
compiled. (The features labeled “Special Form”
instead of “Function” in this manual are macros.) A
loop using incf a hundred times will execute
considerably faster if compiled, and will also garbage-collect
less because the macro expansion will not have to be generated,
used, and thrown away a hundred times.
You can find out how a macro expands by using the
cl-prettyexpand function.
This function takes a single Lisp form as an argument and inserts a nicely formatted copy of it in the current buffer (which must be in Lisp mode so that indentation works properly). It also expands all Lisp macros which appear in the form. The easiest way to use this function is to go to the
*scratch*buffer and type, say,(cl-prettyexpand '(loop for x below 10 collect x))and type C-x C-e immediately after the closing parenthesis; the expansion
(block nil (let* ((x 0) (G1004 nil)) (while (< x 10) (setq G1004 (cons x G1004)) (setq x (+ x 1))) (nreverse G1004)))will be inserted into the buffer. (The
blockmacro is expanded differently in the interpreter and compiler, socl-prettyexpandjust leaves it alone. The temporary variableG1004was created bygensym.)If the optional argument full is true, then all macros are expanded, including
block,eval-when, and compiler macros. Expansion is done as if form were a top-level form in a file being compiled. For example,(cl-prettyexpand '(pushnew 'x list)) -| (setq list (adjoin 'x list)) (cl-prettyexpand '(pushnew 'x list) t) -| (setq list (if (memq 'x list) list (cons 'x list))) (cl-prettyexpand '(caddr (member* 'a list)) t) -| (car (cdr (cdr (memq 'a list))))Note that
adjoin,caddr, andmember*all have built-in compiler macros to optimize them in common cases.
Common Lisp compliance has in general not been sacrificed for the sake of efficiency. A few exceptions have been made for cases where substantial gains were possible at the expense of marginal incompatibility.
The Common Lisp standard (as embodied in Steele's book) uses
the phrase “it is an error if” to indicate a
situation which is not supposed to arise in complying programs;
implementations are strongly encouraged but not required to
signal an error in these situations. This package sometimes omits
such error checking in the interest of compactness and
efficiency. For example, do variable specifiers are
supposed to be lists of one, two, or three forms; extra forms are
ignored by this package rather than signaling a syntax error. The
endp function is simply a synonym for
null in this package. Functions taking keyword
arguments will accept an odd number of arguments, treating the
trailing keyword as if it were followed by the value
nil.
Argument lists (as processed by defun* and
friends) are checked rigorously except for the minor
point just mentioned; in particular, keyword arguments are
checked for validity, and &allow-other-keys and
:allow-other-keys are fully implemented. Keyword
validity checking is slightly time consuming (though not too bad
in byte-compiled code); you can use
&allow-other-keys to omit this check. Functions
defined in this package such as find and
member* do check their keyword arguments for
validity.
Use of the optimizing Emacs compiler is
highly recommended; many of the Common Lisp macros emit code
which can be improved by optimization. In particular,
blocks (whether explicit or implicit in constructs
like defun* and loop) carry a fair
run-time penalty; the optimizing compiler removes
blocks which are not actually referenced by
return or return-from inside the
block.